#ifndef __DEVICE_DISK_H_
#define __DEVICE_DISK_H_

#include <string>
#include <memory>
#include <set>

namespace device {
  // Error (number,message) pair
  struct sErrorInfo {
    int no;           ///< Error number
    std::string msg;  ///< Error message

    explicit sErrorInfo(int n = 0) : no(n) {}
    sErrorInfo(int n, const char *m) : no(n), msg(m) {}
    void clear() { no = 0; msg.clear(); }
    void reset(int n, const char *m) { no = n; msg = m; }
  };

  class Disk {
    public: // enum, struct...
      // disk type (ata, sscsi, nvme..)
      enum class eType : uint8_t {
        unknown, ata, scsi, nvme
      };
      
      // disk base info
      struct sBaseInfo {
        std::string vendor;
        std::string product;
        uint64_t sectors;
        uint64_t size;
      };

      // disk information
      struct sInquiry {
        std::string vendor;
        std::string product;
        std::string version;
      };

    public: // static function...
      // scan disks
      static bool scan_disk(std::set<std::string> &disks);

      // Return disk object for disk 'name'.
      // Return 0 on error.
      static std::shared_ptr<Disk> get_disk(const char * name);
      
      // Get last error info struct.
      static const sErrorInfo& get_err();

      //Return if disk exist. name: /dev/sda or sda
      static bool disk_exist(const char * name);

    public:
      // Return true if disk is open.
      virtual bool is_open() const = 0;
      // Open disk, return false on error.
      virtual bool open() = 0;
      // Close disk, return false on error.
      virtual bool close() = 0;

      virtual bool get_base_info(sBaseInfo &info) = 0;
      virtual bool get_inquiry(sInquiry &info) = 0;
    public: // interface
      // Return disk type
      virtual const eType& get_type() const = 0;

      // Return disk type string
      virtual const char * get_type_str() const = 0;

      // Return Device (path)name
      virtual const char * get_dev() const = 0;

  };

}

#endif
